/**
 * Intelligent Agent Selector
 * Analyzes tasks and intelligently selects the most appropriate agents for execution
 * Uses task type identification and agent capability matching
 */

import { ParallelTaskInfo } from '../types.js';
import { ExternalAgentInfo } from './external-agent-system.js';

export enum TaskType {
  // Development types
  BACKEND_DEVELOPMENT = 'backend',
  FRONTEND_DEVELOPMENT = 'frontend',
  API_DEVELOPMENT = 'api',
  DATABASE_DEVELOPMENT = 'database',

  // Testing types
  UNIT_TEST = 'unit-test',
  INTEGRATION_TEST = 'integration-test',
  E2E_TEST = 'e2e-test',
  PERFORMANCE_TEST = 'performance-test',

  // Build and deployment types
  BUILD = 'build',
  DEPLOY = 'deploy',
  RELEASE = 'release',
  CI_CD = 'ci-cd',

  // Quality and analysis types
  SECURITY_SCAN = 'security-scan',
  QUALITY_CHECK = 'quality-check',
  CODE_REVIEW = 'code-review',

  // Optimization types
  REFACTOR = 'refactor',
  PERFORMANCE_OPTIMIZE = 'optimize',

  // Analysis and debugging types
  DEBUG = 'debug',
  ANALYZE = 'analyze',
  ROOT_CAUSE_ANALYSIS = 'root-cause',

  // Coordination types
  PARALLEL_COORDINATION = 'parallel-coordination',
  WORKFLOW_MANAGEMENT = 'workflow'
}

export interface AgentCapabilityScore {
  agentName: string;
  score: number;
  matchedCapabilities: string[];
  reasoning: string;
  priority: number;
}

export interface AgentSelectionResult {
  selectedAgents: string[];
  alternativeAgents: string[];
  reasoning: string;
  confidenceScore: number;
  taskTypes: TaskType[];
}

export class IntelligentAgentSelector {
  private agentCapabilities: Map<string, string[]> = new Map();
  private agentPriorities: Map<string, number> = new Map();

  constructor() {
    this.initializeAgentCapabilities();
  }

  private initializeAgentCapabilities(): void {
    // CCPM Agents
    this.setAgentCapabilities('parallel-worker', [
      'parallel-coordination', 'workflow', 'task-management', 'coordination', 'execution-management'
    ], 10); // Highest priority for coordination

    this.setAgentCapabilities('test-runner', [
      'unit-test', 'integration-test', 'e2e-test', 'testing', 'test-analysis', 'quality-check'
    ], 9);

    this.setAgentCapabilities('code-analyzer', [
      'analyze', 'code-review', 'debug', 'static-analysis', 'bug-detection'
    ], 8);

    this.setAgentCapabilities('file-analyzer', [
      'analyze', 'file-processing', 'data-extraction', 'log-analysis'
    ], 7);

    // SuperClaude Agents
    this.setAgentCapabilities('backend-architect', [
      'backend', 'api', 'database', 'architecture', 'system-design', 'reliability'
    ], 9);

    this.setAgentCapabilities('frontend-architect', [
      'frontend', 'ui', 'ux', 'client-side', 'user-interface'
    ], 9);

    this.setAgentCapabilities('quality-engineer', [
      'quality-check', 'testing', 'quality-assurance', 'test-strategy', 'edge-case-detection'
    ], 8);

    this.setAgentCapabilities('devops-architect', [
      'deploy', 'ci-cd', 'infrastructure', 'automation', 'build', 'release'
    ], 8);

    this.setAgentCapabilities('security-engineer', [
      'security-scan', 'security', 'vulnerability-analysis', 'penetration-testing'
    ], 8);

    this.setAgentCapabilities('performance-engineer', [
      'performance-test', 'optimize', 'performance-analysis', 'scaling', 'load-testing'
    ], 8);

    this.setAgentCapabilities('refactoring-expert', [
      'refactor', 'code-optimization', 'technical-debt', 'code-improvement'
    ], 7);

    this.setAgentCapabilities('root-cause-analyst', [
      'debug', 'root-cause', 'problem-solving', 'issue-investigation', 'troubleshooting'
    ], 8);

    this.setAgentCapabilities('python-expert', [
      'python', 'backend', 'script-automation', 'python-specific'
    ], 6);
  }

  private setAgentCapabilities(agentName: string, capabilities: string[], priority: number): void {
    this.agentCapabilities.set(agentName, capabilities);
    this.agentPriorities.set(agentName, priority);
  }

  selectAgentsForTask(
    task: ParallelTaskInfo,
    taskTypes: TaskType[],
    availableAgents: string[] = [],
    maxAgents: number = 3
  ): AgentSelectionResult {

    // Filter available agents to only those we know about
    const knownAvailableAgents = availableAgents.filter(agent =>
      this.agentCapabilities.has(agent)
    );

    if (knownAvailableAgents.length === 0) {
      return {
        selectedAgents: [],
        alternativeAgents: [],
        reasoning: 'No known agents available for selection',
        confidenceScore: 0,
        taskTypes
      };
    }

    // Score each available agent for this task
    const agentScores = this.scoreAgentsForTask(task, taskTypes, knownAvailableAgents);

    // Sort by score (descending) and priority (descending)
    agentScores.sort((a, b) => {
      if (Math.abs(a.score - b.score) < 0.1) {
        return b.priority - a.priority; // Higher priority first
      }
      return b.score - a.score; // Higher score first
    });

    // Select top agents
    const selectedAgents = agentScores
      .slice(0, maxAgents)
      .filter(score => score.score > 0.3) // Minimum threshold
      .map(score => score.agentName);

    // Alternative agents (next best options)
    const alternativeAgents = agentScores
      .slice(maxAgents)
      .filter(score => score.score > 0.2)
      .map(score => score.agentName)
      .slice(0, 3);

    // Calculate confidence score
    const confidenceScore = this.calculateConfidenceScore(agentScores, taskTypes);

    // Generate reasoning
    const reasoning = this.generateSelectionReasoning(task, taskTypes, agentScores.slice(0, maxAgents));

    return {
      selectedAgents,
      alternativeAgents,
      reasoning,
      confidenceScore,
      taskTypes
    };
  }

  private scoreAgentsForTask(
    task: ParallelTaskInfo,
    taskTypes: TaskType[],
    availableAgents: string[]
  ): AgentCapabilityScore[] {

    const scores: AgentCapabilityScore[] = [];

    for (const agentName of availableAgents) {
      const agentCapabilities = this.agentCapabilities.get(agentName) || [];
      const agentPriority = this.agentPriorities.get(agentName) || 5;

      let totalScore = 0;
      const matchedCapabilities: string[] = [];

      // Score based on task type matches
      for (const taskType of taskTypes) {
        const taskTypeStr = taskType.toString();
        if (agentCapabilities.includes(taskTypeStr)) {
          totalScore += 1.0; // Perfect match
          matchedCapabilities.push(taskTypeStr);
        }
      }

      // Score based on task description keywords
      const taskDescription = task.description.toLowerCase();
      for (const capability of agentCapabilities) {
        if (taskDescription.includes(capability.toLowerCase().replace('-', ' ')) ||
            taskDescription.includes(capability.toLowerCase().replace('-', ''))) {
          totalScore += 0.5; // Partial match
          if (!matchedCapabilities.includes(capability)) {
            matchedCapabilities.push(capability);
          }
        }
      }

      // Score based on task ID keywords (since TaskInfo doesn't have title)
      const taskId = task.id.toLowerCase();
      for (const capability of agentCapabilities) {
        if (taskId.includes(capability.toLowerCase().replace('-', ' ')) ||
            taskId.includes(capability.toLowerCase().replace('-', ''))) {
          totalScore += 0.3; // Minor match
          if (!matchedCapabilities.includes(capability)) {
            matchedCapabilities.push(capability);
          }
        }
      }

      // Normalize score and apply priority weighting
      const normalizedScore = Math.min(totalScore / Math.max(taskTypes.length, 1), 1.0);
      const priorityWeight = agentPriority / 10.0;
      const finalScore = normalizedScore * 0.8 + priorityWeight * 0.2;

      const reasoning = this.generateAgentScoringReasoning(
        agentName,
        matchedCapabilities,
        normalizedScore,
        agentPriority
      );

      scores.push({
        agentName,
        score: finalScore,
        matchedCapabilities,
        reasoning,
        priority: agentPriority
      });
    }

    return scores;
  }

  private generateAgentScoringReasoning(
    agentName: string,
    matchedCapabilities: string[],
    score: number,
    priority: number
  ): string {
    if (matchedCapabilities.length === 0) {
      return `${agentName} has no direct capability matches but has priority ${priority}`;
    }

    return `${agentName} matches capabilities: ${matchedCapabilities.join(', ')} (score: ${score.toFixed(2)}, priority: ${priority})`;
  }

  private calculateConfidenceScore(scores: AgentCapabilityScore[], taskTypes: TaskType[]): number {
    if (scores.length === 0) return 0;

    // Base confidence on the top agent's score
    const topScore = scores[0]?.score || 0;

    // Boost confidence if we have good coverage of task types
    const totalCapabilities = scores[0]?.matchedCapabilities.length || 0;
    const coverageBonus = Math.min(totalCapabilities / Math.max(taskTypes.length, 1), 1.0) * 0.2;

    // Boost confidence if we have multiple good agents
    const multiAgentBonus = scores.filter(s => s.score > 0.5).length > 1 ? 0.1 : 0;

    return Math.min(topScore + coverageBonus + multiAgentBonus, 1.0);
  }

  private generateSelectionReasoning(
    task: ParallelTaskInfo,
    taskTypes: TaskType[],
    topScores: AgentCapabilityScore[]
  ): string {
    if (topScores.length === 0) {
      return 'No suitable agents found for this task';
    }

    let reasoning = `Selected agents for task "${task.description}":\n\n`;

    reasoning += `Detected task types: ${taskTypes.join(', ')}\n\n`;

    for (const score of topScores) {
      if (score.score > 0.3) {
        reasoning += `• ${score.agentName}: ${score.reasoning}\n`;
      }
    }

    return reasoning;
  }

  // Utility methods

  addAgentCapabilities(agentName: string, capabilities: string[], priority: number = 5): void {
    this.setAgentCapabilities(agentName, capabilities, priority);
  }

  updateAgentPriority(agentName: string, priority: number): void {
    if (this.agentCapabilities.has(agentName)) {
      this.agentPriorities.set(agentName, priority);
    }
  }

  getAgentCapabilities(agentName: string): string[] {
    return this.agentCapabilities.get(agentName) || [];
  }

  getAllKnownAgents(): string[] {
    return Array.from(this.agentCapabilities.keys());
  }

  getAgentsByCapability(capability: string): string[] {
    const agents: string[] = [];

    for (const [agentName, capabilities] of this.agentCapabilities) {
      if (capabilities.includes(capability)) {
        agents.push(agentName);
      }
    }

    return agents.sort((a, b) => {
      const priorityA = this.agentPriorities.get(a) || 5;
      const priorityB = this.agentPriorities.get(b) || 5;
      return priorityB - priorityA; // Higher priority first
    });
  }

  // For coordination tasks, always ensure parallel-worker is included
  ensureCoordinationAgent(selectedAgents: string[]): string[] {
    if (!selectedAgents.includes('parallel-worker') &&
        this.agentCapabilities.has('parallel-worker')) {
      return ['parallel-worker', ...selectedAgents.slice(0, 2)];
    }
    return selectedAgents;
  }

  // Get recommended agent combinations for common scenarios
  getRecommendedCombinations(): Record<string, string[]> {
    return {
      'full-stack-development': ['parallel-worker', 'backend-architect', 'frontend-architect'],
      'testing-focus': ['parallel-worker', 'test-runner', 'quality-engineer'],
      'deployment-focus': ['parallel-worker', 'devops-architect', 'security-engineer'],
      'performance-focus': ['parallel-worker', 'performance-engineer', 'backend-architect'],
      'quality-focus': ['parallel-worker', 'quality-engineer', 'code-analyzer'],
      'debug-focus': ['parallel-worker', 'root-cause-analyst', 'code-analyzer']
    };
  }
}